package com.xkh.common.controller;


import com.xkh.common.common.constant.Result;
import com.xkh.common.entity.DemoData;
import com.xkh.common.util.TimeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 许克弘
 * @date 2021/6/20 21:01
 * redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合),zset(sorted set 有序集合)
 * redis默认支持16个数据库，不适用于根据业务存放不同的数据库，适用于比如测试环境用1数据库，正式用2数据库，因为比如FLUSH命令可以清空Redis实例所有数据库中的数据
 */
@RestController
@RequestMapping("util/redis")
@Api(tags = "redis模块")
@Slf4j
public class RedisController {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;


    @ApiOperation("redis计数器")
    @GetMapping("/getCounter")
    public Result<DemoData> getCounter(){
        Long userId = 100L;
        String dateStr = TimeUtil.getDateStr();
        Long count = (Long) redisTemplate.opsForHash().get("getCounter"+userId+dateStr,userId);
        if(ObjectUtils.isEmpty(count)){
            Long increment = redisTemplate.opsForHash().increment("getCounter:"+userId,userId,1);
                return Result.otherSuccess(increment);
        }else {
            return Result.otherSuccess(count);
        }

    }

    @ApiOperation("redis5种数据类型简单存取数据")
    @GetMapping("/getRedis")
    public Result getRedis() {
        redisTemplate.opsForValue().set("string", "字符串");
        log.info("获取string数据:" + redisTemplate.opsForValue().get("string"));

        //存储hash类型 场景:存储，读取，修改用户属性
        redisTemplate.opsForHash().put("hash", "hash1", "哈希1号");
        redisTemplate.opsForHash().put("hash", "hash2", "哈希2号");
        log.info("获取hash1数据:" + redisTemplate.opsForHash().get("hash", "hash1"));
        log.info("获取hash2数据:" + redisTemplate.opsForHash().get("hash", "hash2"));

        //存储list类型 场景:最新消息排行等功能(比如朋友圈的时间线),消息队列 按照插入顺序排序 可以添加元素到列表的头部(左边)或者尾部(右边)
        redisTemplate.delete("list");
        redisTemplate.opsForList().leftPush("list", "List左数据");
        redisTemplate.opsForList().rightPush("list", "List右数据");
        Long length = redisTemplate.opsForList().size("list");
        List<Object> list = redisTemplate.opsForList().range("list", 0, length);
        log.info("此Key一共" + length + "条数据" + " 获取List数据:" + Arrays.asList(list));

        //存储set类型 场景:共同好友,利用唯一性，统计访问网站的所有独立IP
        redisTemplate.opsForSet().add("set", "set1号", "set2号", "set2号");
        Set<Object> set = redisTemplate.opsForSet().members("set");
        log.info("获取Set数据:" + Arrays.asList(set));

        //存储zset类型 场景:排行榜，带权重的消息队列 每个类型都会关联一个double类型的分数(可重复)，redis通过分数来为集合中的成员进行从小到大的排序
        Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
        ZSetOperations.TypedTuple<Object> tuple1 = new DefaultTypedTuple<>("tuple1", 1D);
        tuples.add(tuple1);
        ZSetOperations.TypedTuple<Object> tuple3 = new DefaultTypedTuple<>("tuple3", 3D);
        tuples.add(tuple3);
        ZSetOperations.TypedTuple<Object> tuple2 = new DefaultTypedTuple<>("tuple2", 2D);
        tuples.add(tuple2);
        redisTemplate.opsForZSet().add("zSet",tuples);
        Long lengthSet = redisTemplate.opsForZSet().size("zSet");
        Set zSet = redisTemplate.opsForZSet().range("zSet",0,lengthSet);
        log.info("此Key一共"+lengthSet+"获取zSet数据:" + Arrays.asList(zSet));
        return Result.succeed();
    }
}
